/*     */ package com.zimbra.cs.store;
/*     */ 
/*     */ import com.google.common.annotations.VisibleForTesting;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.mime.MimePart.InputStreamSource;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import java.io.File;
/*     */ import java.io.FileNotFoundException;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import javax.mail.internet.SharedInputStream;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class BlobInputStream
/*     */   extends InputStream
/*     */   implements SharedInputStream, MimePart.InputStreamSource
/*     */ {
/*  35 */   private static final Log sLog = LogFactory.getLog(BlobInputStream.class);
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private File mFile;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private final long mRawSize;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  54 */   private long mMarkPos = Long.MIN_VALUE;
/*     */   
/*     */ 
/*     */ 
/*     */   private long mPos;
/*     */   
/*     */ 
/*     */ 
/*     */   private int mMarkReadLimit;
/*     */   
/*     */ 
/*     */ 
/*     */   private long mStart;
/*     */   
/*     */ 
/*     */ 
/*     */   private long mEnd;
/*     */   
/*     */ 
/*     */ 
/*     */   private BlobInputStream mRoot;
/*     */   
/*     */ 
/*     */ 
/*  78 */   private static int BUFFER_SIZE = Math.max(LC.zimbra_blob_input_stream_buffer_size_kb.intValue(), 1) * 1024;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*  83 */   private final byte[] mBuf = new byte[BUFFER_SIZE];
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*  88 */   private long mBufPos = 0L;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  94 */   private int mBufSize = 0;
/*     */   private static FileDescriptorCache mFileDescriptorCache;
/*     */   
/*     */   public BlobInputStream(Blob blob)
/*     */     throws IOException
/*     */   {
/* 100 */     this(blob.getFile(), blob.getRawSize(), null, null, null);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public BlobInputStream(File file, long rawSize)
/*     */     throws IOException
/*     */   {
/* 109 */     this(file, rawSize, null, null, null);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   @VisibleForTesting
/*     */   public BlobInputStream(File file, long rawSize, Long start, Long end)
/*     */     throws IOException
/*     */   {
/* 121 */     this(file, rawSize, start, end, null);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected BlobInputStream(File file, long rawSize, Long start, Long end, BlobInputStream parent)
/*     */     throws IOException
/*     */   {
/* 135 */     if (parent == null)
/*     */     {
/* 137 */       this.mFile = file;
/* 138 */       this.mRoot = this;
/* 139 */       if (!file.exists()) {
/* 140 */         throw new FileNotFoundException(file.getPath() + " does not exist");
/*     */       }
/*     */     }
/*     */     else {
/* 144 */       setMailboxLocator(parent);
/* 145 */       this.mRoot = parent.mRoot;
/* 146 */       file = parent.getRootFile();
/* 147 */       if ((!file.exists()) && (!getFileDescriptorCache().contains(file.getPath()))) {
/* 148 */         throw new FileNotFoundException(file.getPath() + " does not exist");
/*     */       }
/*     */     }
/* 151 */     this.mRawSize = rawSize;
/*     */     
/* 153 */     if ((start != null) && (end != null) && (start.longValue() > end.longValue())) {
/* 154 */       String msg = String.format("Start index %d for file %s is larger than end index %d", new Object[] { start, file.getPath(), end });
/* 155 */       throw new IOException(msg);
/*     */     }
/* 157 */     if (start == null) {
/* 158 */       this.mStart = 0L;
/* 159 */       this.mPos = 0L;
/*     */     } else {
/* 161 */       this.mStart = start.longValue();
/* 162 */       this.mPos = start.longValue();
/*     */     }
/* 164 */     if (end == null) {
/* 165 */       this.mEnd = this.mRawSize;
/*     */     } else {
/* 167 */       if (end.longValue() > this.mRawSize) {
/* 168 */         String msg = String.format("End index %d for %s exceeded file size %d", new Object[] { end, file.getPath(), Long.valueOf(this.mRawSize) });
/* 169 */         throw new IOException(msg);
/*     */       }
/* 171 */       this.mEnd = end.longValue();
/*     */     }
/*     */     
/* 174 */     sLog.debug("Created %s: file=%s, length=%d, uncompressed length=%d, start=%d, end=%d, parent=%s, mStart=%d, mEnd=%d.", new Object[] { this, file.getPath(), Long.valueOf(file.length()), Long.valueOf(this.mRawSize), start, end, parent, Long.valueOf(this.mStart), Long.valueOf(this.mEnd) });
/*     */   }
/*     */   
/*     */   protected File getRootFile() throws IOException
/*     */   {
/* 179 */     return this.mRoot.mFile;
/*     */   }
/*     */   
/*     */   protected void setMailboxLocator(BlobInputStream parent) {}
/*     */   
/*     */   protected BlobInputStream initializeSubStream(File file, long rawSize, Long start, Long end, BlobInputStream parent)
/*     */     throws IOException
/*     */   {
/* 187 */     return new BlobInputStream(file, rawSize, start, end, parent);
/*     */   }
/*     */   
/*     */ 
/*     */   public static void setFileDescriptorCache(FileDescriptorCache fdcache)
/*     */   {
/* 193 */     mFileDescriptorCache = fdcache;
/*     */   }
/*     */   
/*     */   public static FileDescriptorCache getFileDescriptorCache() {
/* 197 */     return mFileDescriptorCache;
/*     */   }
/*     */   
/*     */ 
/*     */   public void closeFile()
/*     */   {
/*     */     try
/*     */     {
/* 205 */       getFileDescriptorCache().remove(getRootFile().getPath());
/*     */     } catch (IOException e) {
/* 207 */       sLog.warn("Unable to close mRoot.mFile", e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public void fileMoved(File newFile)
/*     */   {
/* 215 */     closeFile();
/* 216 */     this.mRoot.mFile = newFile;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public int available()
/*     */   {
/* 223 */     return (int)(this.mEnd - this.mPos);
/*     */   }
/*     */   
/*     */   public void close()
/*     */   {
/* 228 */     this.mPos = this.mEnd;
/*     */   }
/*     */   
/*     */   public synchronized void mark(int readlimit)
/*     */   {
/* 233 */     this.mMarkPos = this.mPos;
/* 234 */     this.mMarkReadLimit = readlimit;
/*     */   }
/*     */   
/*     */   public boolean markSupported()
/*     */   {
/* 239 */     return true;
/*     */   }
/*     */   
/*     */   public int read() throws IOException
/*     */   {
/* 244 */     if (this.mPos >= this.mEnd) {
/* 245 */       return -1;
/*     */     }
/* 247 */     if ((this.mPos < this.mBufPos) || (this.mPos >= this.mBufPos + this.mBufSize))
/*     */     {
/* 249 */       int numRead = fillBuffer(this.mPos);
/* 250 */       if (numRead <= 0) {
/* 251 */         return -1;
/*     */       }
/*     */     }
/* 254 */     byte b = this.mBuf[((int)(this.mPos - this.mBufPos))];
/* 255 */     this.mPos += 1L;
/* 256 */     return b & 0xFF;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private int fillBuffer(long pos)
/*     */     throws IOException
/*     */   {
/* 264 */     int numToRead = (int)Math.min(this.mBuf.length, this.mEnd - pos);
/* 265 */     int numRead = getFileDescriptorCache().read(getRootFile().getPath(), this.mRawSize, pos, this.mBuf, 0, numToRead);
/* 266 */     if (numRead > 0) {
/* 267 */       this.mBufPos = pos;
/* 268 */       this.mBufSize = numRead;
/*     */     } else {
/* 270 */       this.mBufSize = 0;
/*     */     }
/* 272 */     return numRead;
/*     */   }
/*     */   
/*     */   public int read(byte[] b, int off, int len) throws IOException
/*     */   {
/* 277 */     if (this.mPos >= this.mEnd) {
/* 278 */       return -1;
/*     */     }
/* 280 */     if (len <= 0) {
/* 281 */       return 0;
/*     */     }
/*     */     
/*     */ 
/* 285 */     len = (int)Math.min(len, this.mEnd - this.mPos);
/* 286 */     int numRead = 0;
/*     */     
/* 288 */     if ((this.mPos >= this.mBufPos) && (this.mPos < this.mBufPos + this.mBufSize))
/*     */     {
/* 290 */       numRead = (int)Math.min(len, this.mBufPos + this.mBufSize - this.mPos);
/* 291 */       int bufStartIndex = (int)(this.mPos - this.mBufPos);
/* 292 */       System.arraycopy(this.mBuf, bufStartIndex, b, off, numRead);
/*     */     }
/* 294 */     else if (len > this.mBuf.length)
/*     */     {
/* 296 */       numRead = getFileDescriptorCache().read(getRootFile().getPath(), this.mRawSize, this.mPos, b, off, len);
/*     */     }
/*     */     else {
/* 299 */       int numReadIntoBuffer = fillBuffer(this.mPos);
/* 300 */       if (numReadIntoBuffer <= 0) {
/* 301 */         return -1;
/*     */       }
/* 303 */       System.arraycopy(this.mBuf, 0, b, off, len);
/* 304 */       numRead = len;
/*     */     }
/*     */     
/* 307 */     if (numRead > 0) {
/* 308 */       this.mPos += numRead;
/*     */     } else {
/* 310 */       close();
/*     */     }
/* 312 */     return numRead;
/*     */   }
/*     */   
/*     */   public synchronized void reset() throws IOException
/*     */   {
/* 317 */     if (this.mMarkPos == Long.MIN_VALUE) {
/* 318 */       throw new IOException("reset() called before mark()");
/*     */     }
/* 320 */     if (this.mPos - this.mMarkPos > this.mMarkReadLimit) {
/* 321 */       throw new IOException("Mark position was invalidated because more than " + this.mMarkReadLimit + " bytes were read.");
/*     */     }
/* 323 */     this.mPos = this.mMarkPos;
/*     */   }
/*     */   
/*     */   public long skip(long n)
/*     */   {
/* 328 */     if (n <= 0L) {
/* 329 */       return 0L;
/*     */     }
/* 331 */     long newPos = Math.min(this.mPos + n, this.mEnd);
/* 332 */     long numSkipped = newPos - this.mPos;
/* 333 */     this.mPos = newPos;
/* 334 */     return numSkipped;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected void finalize()
/*     */     throws Throwable
/*     */   {
/* 344 */     super.finalize();
/* 345 */     close();
/*     */   }
/*     */   
/*     */ 
/*     */   public long getSize()
/*     */   {
/* 351 */     return this.mEnd - this.mStart;
/*     */   }
/*     */   
/*     */ 
/*     */   public long getPosition()
/*     */   {
/* 357 */     return this.mPos - this.mStart;
/*     */   }
/*     */   
/*     */   public InputStream newStream(long start, long end)
/*     */   {
/* 362 */     if (start < 0L) {
/* 363 */       throw new IllegalArgumentException("start cannot be less than 0");
/*     */     }
/*     */     
/*     */ 
/*     */ 
/* 368 */     start += this.mStart;
/* 369 */     if (end < 0L) {
/* 370 */       end = this.mEnd;
/*     */     } else {
/* 372 */       end += this.mStart;
/*     */     }
/*     */     
/* 375 */     BlobInputStream newStream = null;
/*     */     try {
/* 377 */       newStream = initializeSubStream(null, this.mRawSize, Long.valueOf(start), Long.valueOf(end), this);
/*     */     } catch (IOException e) {
/* 379 */       sLog.warn("Unable to create substream for %s", this.mRoot.mFile.getPath(), e);
/*     */     }
/*     */     
/* 382 */     return newStream;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/store/BlobInputStream.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */